<template>
  <div
    class="h-select"
    :class="{
      'is-disabled': disabled,
    }"
    @click="toggleDropdownFun"
    @mouseenter="mouseState = true"
    @mouseleave="mouseState = false"
  >
    <h-tooltip
      placement="bottom-start"
      manual
      ref="tooltipRef"
      :optionsPlacement="popperOptions"
      @click-outside="controlDropdown(false)"
    >
      <h-input
        v-model="inputValue"
        :disabled
        :placeholder="filterPlaceholder"
        ref="inputRef"
        :readonly="!filterable"
        @input="debounceFilter"
        @keydown="handleKeydown"
      >
        <template #suffix>
          <h-icon
            v-if="isShowClear"
            icon="circle-xmark"
            class="h-input__clear"
            @click.stop="clearFun"
            @mousedown.prevent="TIP"
          />
          <h-icon
            v-else
            icon="angle-down"
            class="header-angle"
            :class="{ 'is-active': isDropdown }"
          />
        </template>
      </h-input>
      <template #content>
        <div class="h-select__loading" v-if="loading">
          <h-icon icon="spinner" spin />
        </div>
        <div
          class="h-select__nodata"
          v-else-if="filterable && copyOptions.length === 0"
        >
          no matching data
        </div>
        <ul class="h-select__menu" v-else>
          <template v-for="(item, index) in copyOptions" :key="index">
            <li
              class="h-select__menu-item"
              :class="{
                'is-disabled': item.disabled,
                'is-selected': item.value == modelValue,
                'is-highlighted': highlightIndex === index,
              }"
              :id="`select-item-${item.value}`"
              @click.stop="clickItemFun(item)"
            >
              <RenderVnode
                :v-node="renderLabel ? renderLabel(item) : item.label"
              ></RenderVnode>
            </li>
          </template>
        </ul>
      </template>
    </h-tooltip>
  </div>
</template>

<script setup lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */
import { computed, ref, watch, type Ref } from "vue";
import type { SelectProps, SelectEmits, SelectOption } from "./types";
import HTooltip from "../Tooltip/HTooltip.vue";
import HInput from "../Input/HInput.vue";
import type { TooltipManual } from "../Tooltip/types";
import type { InputExpose } from "../Input/types";
import HIcon from "../Icon/HIcon.vue";
import RenderVnode from "@/common/renderVNode";
import { isFunction, debounce } from "lodash";

const modelValue = defineModel<string>();
const {
  remote,
  remoteMethod,
  disabled,
  options = [],
  clearable,
  filterable,
  filterMethod,
  placeholder,
} = defineProps<SelectProps>();
const emits = defineEmits<SelectEmits>();
const inputRef = ref<InputExpose>();
const tooltipRef = ref() as Ref<TooltipManual>;
// 下拉框是否显示
const isDropdown = ref(false);
// 鼠标是否进入select组件
const mouseState = ref(false);
const loading = ref(false);
const highlightIndex = ref(-1);

// 使下拉框与input框对齐
const popperOptions: any = {
  modifiers: [
    {
      name: "offset",
      options: {
        offset: [0, 9],
      },
    },
    {
      name: "sameWidth",
      enabled: true,
      fn: ({ state }: { state: any }) => {
        state.styles.popper.width = `${state.rects.reference.width}px`;
      },
      phase: "beforeWrite",
      requires: ["computeStyles"],
    },
  ],
};

//查找指定option
const findOption = (value: string | undefined) => {
  const opiton = options.find((item) => item.value == value);
  return opiton ? opiton : null;
};
// 当前选中option
let currentOption = findOption(modelValue.value);
// input v-model
const inputValue = ref(currentOption ? currentOption.label : "");
// 过滤后的值
const copyOptions = ref(options);

watch(
  () => options,
  (newValue) => {
    copyOptions.value = newValue;
  }
);

const time = computed(() => (remote && remoteMethod ? 300 : 0));

// 筛选功能快速查找选项
const filterOptionsFun = async (item: string) => {
  if (!filterable) return;
  if (filterMethod && isFunction(filterMethod)) {
    copyOptions.value = filterMethod(item);
  } else if (remote && remoteMethod && isFunction(remoteMethod)) {
    try {
      loading.value = true;
      copyOptions.value = await remoteMethod(item);
    } catch (error) {
      console.log(error);
      copyOptions.value = [];
    } finally {
      loading.value = false;
    }
  } else {
    copyOptions.value = options.filter((i) => {
      console.log(i.label);

      console.log(i.label.includes(item));

      return i.label.includes(item);
    });
  }
  highlightIndex.value = -1;
};

// 处理键盘事件
const handleKeydown = (e: KeyboardEvent) => {
  switch (e.key) {
    case "Enter":
      if (!isDropdown.value) {
        controlDropdown(true);
      } else {
        if (
          highlightIndex.value > -1 &&
          copyOptions.value[highlightIndex.value]
        ) {
          clickItemFun(copyOptions.value[highlightIndex.value]);
        } else {
          controlDropdown(false);
        }
      }
      break;
    case "Escape":
      if (isDropdown.value) {
        controlDropdown(false);
      }
      break;
    case "ArrowUp":
      e.preventDefault();
      // states.highlightIndex = -1
      if (copyOptions.value.length > 0) {
        if (highlightIndex.value === -1 || highlightIndex.value === 0) {
          highlightIndex.value = copyOptions.value.length - 1;
        } else {
          // move up
          highlightIndex.value--;
        }
      }
      break;
    case "ArrowDown":
      e.preventDefault();
      // states.highlightIndex = -1
      if (copyOptions.value.length > 0) {
        if (
          highlightIndex.value === -1 ||
          highlightIndex.value === copyOptions.value.length - 1
        ) {
          highlightIndex.value = 0;
        } else {
          // move up
          highlightIndex.value++;
        }
      }
      break;
    default:
      break;
  }
};

// 搜索防抖
const debounceFilter = debounce(() => {
  filterOptionsFun(inputValue.value);
}, time.value);

// input筛选状态，筛选后显示筛选placeholder之前的label
const filterPlaceholder = computed(() => {
  return filterable && currentOption && isDropdown.value
    ? currentOption.label
    : placeholder;
});

// 判断是否显示清除图标
const isShowClear = computed(
  () =>
    mouseState.value && inputValue.value.trim() != "" && !disabled && clearable
);

// 点击清除图标事件
const clearFun = () => {
  modelValue.value = "";
  inputValue.value = "";
  currentOption = null;
  emits("change", "");
  emits("clear");
};

const TIP = () => {};

// 控制下拉框显示函数
const controlDropdown = (show: boolean) => {
  if (show) {
    if (filterable && currentOption) {
      inputValue.value = "";
    }
    // 进行一次默认选项生成
    if (filterable) {
      filterOptionsFun(inputValue.value);
    }
    tooltipRef.value.show();
  } else {
    // blur时候将之前的值回灌到input中
    if (filterable) {
      console.log(currentOption);

      inputValue.value = currentOption ? currentOption.label : "";
    }
    tooltipRef.value.hide();
  }
  highlightIndex.value = -1;
  isDropdown.value = show;
  emits("visible-change", isDropdown.value);
};

// 点击切换下拉框显示与不显示函数
const toggleDropdownFun = () => {
  if (disabled) return;
  if (isDropdown.value) {
    controlDropdown(false);
  } else {
    controlDropdown(true);
  }
};

// 点击Option选项事件
const clickItemFun = (e: SelectOption) => {
  if (e.disabled) return;
  inputValue.value = e.label;
  modelValue.value = e.value;
  currentOption = e;
  controlDropdown(false);
  emits("change", e.value);
  inputRef.value?.ref.focus();
};
</script>

<style scoped></style>
